package com.hwy.chart.cursor

import android.graphics.*
import androidx.annotation.ColorInt
import androidx.annotation.IntDef
import androidx.annotation.MainThread
import com.hwy.chart.BaseChartView
import kotlin.math.max
import kotlin.math.min

/**
 * =======================================
 * 作者: hewenyu
 * 日期: 2022/5/10 15:34
 * 说明: 光标基础组件
 * =======================================
 */
abstract class BaseCursor(protected val chartView: BaseChartView) {

    companion object {

        /**
         * 无效的光标位置，当坐标设置为该值时，光标不绘制
         */
        const val INVALID_COORDINATE = Float.MIN_VALUE

        /**
         * 光标绘制的模式：支持横向光标
         */
        const val MODEL_HORIZONTAL = 0x01

        /**
         * 光标绘制的模式：支持纵向光标
         */
        const val MODEL_VERTICAL = 0x02

        /**
         * 光标绘制的模式：支持横向和纵向的光标
         */
        const val MODEL_ALL = MODEL_HORIZONTAL.or(MODEL_VERTICAL)

        /**
         * 光标模式泛型约束
         */
        @IntDef(MODEL_HORIZONTAL, MODEL_VERTICAL, MODEL_ALL)
        annotation class CursorModel

    }

    /**
     * 光标切换事件监听对象列表
     */
    private val cursorChangeListenerList by lazy {
        ArrayList<OnCursorChangeListener>()
    }

    protected val cursorPaint by lazy {
        Paint().apply {
            isAntiAlias = true
            isDither = true
            style = Paint.Style.FILL_AND_STROKE
        }
    }

    /**
     * 是否允许绘制光标
     *
     * true: 允许绘制光标
     * false:禁止绘制光标 (默认，没有touch事件时不允许绘制)
     */
    var isCursorEnable = false
        set(value) {
            if (field == value) {
                return
            }
            field = value
            chartView.invalidate()
        }

    /**
     * 光标粗细
     */
    var cursorWidth = 2F

    /**
     * 光标颜色
     */
    var cursorColor = Color.RED

    /**
     * 光标绘制的模式
     */
    @CursorModel
    var cursorModel = MODEL_ALL
        set(value) {
            if (field == value) {
                return
            }
            field = value
            chartView.invalidate()
        }

    /**
     * 坐标点位置信息
     *
     * [coordinate.x] 光标绘制的 x坐标，用于绘制纵向光标
     * [coordinate.y] 光标绘制的 y坐标，用于绘制横向光标
     */
    protected val coordinate by lazy {
        PointF(INVALID_COORDINATE, INVALID_COORDINATE)
    }

    /**
     * 光标标签组件
     */
    var cursorTag = CursorTag()

    private var lastIndex: Int? = null

    // region --------------------------------- 坐标信息更新相关函数 ---------------------------------

    /**
     * 更新光标坐标点
     *
     * @param x 光标点的 x坐标
     * @param y 光标点的 y坐标
     */
    open fun updateCoordinate(x: Float?, y: Float?, index: Int?) {
        coordinate.set(x ?: INVALID_COORDINATE, y ?: INVALID_COORDINATE)
        if (lastIndex != index) {
            cursorChangeListenerList.forEach {
                it.onCursorChange(lastIndex, index)
            }
            lastIndex = index
        }
    }

    /**
     * 清空光标坐标点
     */
    fun clearCoordinate() {
        updateCoordinate(null, null, null)
    }

    // endregion ---------------------------------------------------------------------------------

    // region --------------------------------- 光标事件监听相关函数 ---------------------------------

    /**
     * 添加光标变化监听对象
     */
    @MainThread
    fun addCursorChangeListener(listener: OnCursorChangeListener?) {
        listener?.run {
            if (!cursorChangeListenerList.contains(this)) {
                cursorChangeListenerList.add(this)
            }
        }
    }

    /**
     * 移除光标变化监听对象
     */
    @MainThread
    fun removeCursorChangeListener(listener: OnCursorChangeListener?) {
        listener?.run {
            cursorChangeListenerList.remove(this)
        }
    }

    /**
     * 清空光标变化监听对象
     */
    @MainThread
    fun clearCursorChangeListener() {
        cursorChangeListenerList.clear()
    }

    // endregion ----------------------------------------------------------------------------------

    // region --------------------------------- 光标标签设置 ---------------------------------

    /**
     * 设置光标Tag文本内容
     */
    fun updateCursorTag(verticalTag: String = "", horizontalTag: String = "") {
        cursorTag.setTag(verticalTag, horizontalTag)
    }

    /**
     * 设置Tag文本内边距
     */
    fun setTagPadding(
        paddingLeft: Float,
        paddingTop: Float,
        paddingRight: Float,
        paddingBottom: Float
    ) {
        cursorTag.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom)
    }

    /**
     * 设置Tag背景色和圆角属性
     */
    fun setTagShape(@ColorInt color: Int, corner: Float) {
        cursorTag?.run {
            tagColor = color
            tagCorner = corner
        }
    }

    // endregion ---------------------------------------------------------------------------

    // region --------------------------------- 绘制相关函数 ---------------------------------

    /**
     * 绘制光标
     */
    open fun draw(canvas: Canvas, bounds: RectF) {
        if (isCursorEnable) {
            cursorPaint.run {
                color = cursorColor
                strokeWidth = cursorWidth
            }
            // 绘制纵向的光标
            drawVerticalCursor(canvas, bounds)
            // 绘制横向的光标
            drawHorizontalCursor(canvas, bounds)
        }
    }

    /**
     * 绘制纵向的光标
     */
    protected open fun drawVerticalCursor(canvas: Canvas, bounds: RectF) {
        if (cursorModel.and(MODEL_VERTICAL) == 0 || coordinate.x == INVALID_COORDINATE) {
            return
        }
        // 纵向光标的x坐标的上下阈值判断
        var x = max(coordinate.x, bounds.left + cursorWidth / 2F)
        x = min(x, bounds.right - cursorWidth / 2F)
        // 绘制纵向光标
        canvas.drawLine(x, bounds.top, x, bounds.bottom, cursorPaint)
        drawVerticalCursorTag(canvas, bounds, x)
    }

    /**
     * 绘制横向的光标
     */
    protected open fun drawHorizontalCursor(canvas: Canvas, bounds: RectF) {
        if (cursorModel.and(MODEL_HORIZONTAL) == 0 || coordinate.y == INVALID_COORDINATE) {
            return
        }
        // 横向光标的y坐标的上下阈值判断
        var y = max(coordinate.y, bounds.top + cursorWidth / 2F)
        y = min(y, bounds.bottom - cursorWidth / 2F)
        // 绘制横向光标
        canvas.drawLine(bounds.left, y, bounds.right, y, cursorPaint)
        // 绘制光标标签
        drawHorizontalCursorTag(canvas, bounds, y)
    }

    /**
     * 绘制横向标签上的Tag文本
     *
     * @param y 横向光标绘制的 y 坐标
     */
    protected open fun drawHorizontalCursorTag(canvas: Canvas, bounds: RectF, y: Float) {
        // 由子类实现Tag绘制逻辑
    }

    /**
     * 绘制纵向标签上的Tag文本
     *
     * @param x 纵向光标绘制的 x 坐标
     */
    protected open fun drawVerticalCursorTag(canvas: Canvas, bounds: RectF, x: Float) {
        // 由子类实现Tag绘制逻辑
    }

    // endregion ---------------------------------------------------------------------------

}